﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using AForge.Imaging.Filters;
using System.Drawing.Imaging;
using AForge.Imaging;

namespace SimpleGUI.DetectionMethods.Simple2Cameras
{
	/// <summary>
	/// Dart coord detected (should this have its own struct?)
	/// </summary>
	/// <param name="sender"></param>
	/// <param name="coord"></param>
	public delegate void DartCoordEventHandler(object sender, int coord);

	/// <summary>
	/// Class moet event sturen dat er een coord gevonden is in 2D space
	/// </summary>
	class FrameProcessor
	{
		// debug
		private Random r = new Random();

		/// <summary>
		/// New Dart coord detected
		/// </summary>
		public event DartCoordEventHandler CoordDetected;

		/// <summary>
		/// Image width
		/// </summary>
		private int width;

		/// <summary>
		/// image height
		/// </summary>
		private int height;

		#region filters
		private IFilter grayscaleFilter = new GrayscaleBT709();
		private Difference differenceFilter = new Difference();
		private Threshold thresholdFilter = new Threshold(12);
		private IFilter openingFilter = new Opening();
		private IFilter edgesFilter = new Edges();
		private Merge mergeFilter = new Merge();
		private MoveTowards moveTowardsFilter = new MoveTowards();
		private BlobCounter blobCounter = new BlobCounter();


		#endregion

		/// <summary>
		/// The frame we compare agianst
		/// </summary>
		private Bitmap backgroundFrame;
		private BitmapData bitmapData;
		private int counter = 0;

		// wich video source are we processing?
		private int _videoSource;
		public int VideoSource { get { return _videoSource; } }

		/// <summary>
		/// Constructor
		///  - nothing special :P
		/// </summary>
		public FrameProcessor(int videoSource)
		{
			this._videoSource = videoSource;
		}

		/// <summary>
		/// Try detecting a coordinate
		/// </summary>
		/// <param name="image"></param>
		/// <param name="videoSource"></param>
		public void ProcessFrame(ref Bitmap image)
		{
			if (backgroundFrame == null)
			{
				// create initial backgroung image
				backgroundFrame = grayscaleFilter.Apply(image);

				// get image dimension
				width = image.Width;
				height = image.Height;

				// just return for the first time
				return;
			}

			// apply the the grayscale file
			Bitmap tmpImage = grayscaleFilter.Apply(image);

			if (++counter == 2)
			{
				counter = 0;

				// move background towards current frame
				moveTowardsFilter.OverlayImage = tmpImage;
                moveTowardsFilter.StepSize = 3;
				moveTowardsFilter.ApplyInPlace(backgroundFrame);
			}


			// set backgroud frame as an overlay for difference filter
			differenceFilter.OverlayImage = backgroundFrame;

			// lock temporary image to apply several filters
			bitmapData = tmpImage.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed);

			// apply difference filter
			differenceFilter.ApplyInPlace(bitmapData);

			// apply threshold filter
			thresholdFilter.ApplyInPlace(bitmapData);

			// apply opening filter
			Bitmap tmpImage2 = openingFilter.Apply(bitmapData);

			// find blobs
			blobCounter.MinWidth = 5;                     // set minimum size of
			blobCounter.MinHeight = 20;                   // objects we look for
			blobCounter.FilterBlobs = true;               // filter blobs by size
			blobCounter.ObjectsOrder = ObjectsOrder.Size; // order found object by size
			blobCounter.ProcessImage(tmpImage2);
			Rectangle[] rects = blobCounter.GetObjectRectangles();
			if (rects.Length > 0)
			{
				// nu een x tijd niet meer detecten...
				
				Rectangle objectRect = rects[0];
				Graphics g = Graphics.FromImage(image);
				using (Pen pen = new Pen(Color.FromArgb(160, 255, 160), 3))
				{
					//	foreach (Rectangle objectRect in rects)
					g.DrawRectangle(pen, objectRect);
				}
				g.Dispose();


				/*
				if (this.CoordDetected != null)
					this.CoordDetected(this, objectRect.Bottom);
				*/
			}

			// unlock temporary image
			tmpImage.UnlockBits(bitmapData);
			tmpImage.Dispose();

			// merge background frame and camera frame
			//mergeFilter.OverlayImage = backgroundFrame;
			//mergeFilter.ApplyInPlace(tmpImage2);


			// replace camera picture with de detection picture
			//image.Dispose();
			//image = tmpImage2;
		}

		public void reset()
		{
			this.backgroundFrame = null;
			this.counter = 0;
		}
	}
}